/**
 * 
 */
package edu.gtcfla.km.appmodules.service.impl;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.vsg.biz.BusinessEntityFactory;
import org.vsg.biz.BusinessOperationException;
import org.vsg.biz.account.User;
import org.vsg.biz.account.repositories.UserPagingAndSortingRepo;
import org.vsg.common.model.algstrategy.GenTreeModelBuilder;
import org.vsg.common.model.json.TreeNode;
import org.vsg.common.page.PageItemConverter;
import org.vsg.common.page.PaginationManager;
import org.vsg.search.api.criterion.MapPaginaitionCriteria;
import org.vsg.search.api.page.PaginationException;

import edu.gtcfla.km.Category;
import edu.gtcfla.km.UserGroup;
import edu.gtcfla.km.UserGroupPermission;
import edu.gtcfla.km.UserPermission;
import edu.gtcfla.km.appmodules.service.UserPermissionService;
import edu.gtcfla.km.appmodules.vo.CurrentUserCategoryPermissionVO;
import edu.gtcfla.km.appmodules.vo.UserDirectPermissionListVO;
import edu.gtcfla.km.repositories.UserGroupPermissionRepo;
import edu.gtcfla.km.repositories.UserGroupRepo;
import edu.gtcfla.km.repositories.UserPermissionRepo;
import edu.gtcfla.km.security.api.SubjectManager;

/**
 * @author vison
 *
 */
public class UserPermissionServiceI implements UserPermissionService {

	@Autowired(required=false)
	private edu.gtcfla.km.repositories.CategoryRepo<Category,String> categoryRepo;

	@Autowired(required=false)	
	private UserPagingAndSortingRepo<User,String> userRepo;

	@Autowired(required=false)	
	private UserPermissionRepo<UserPermission, String>  upRepo;

	@Autowired(required=false)	
	private UserGroupPermissionRepo<UserGroupPermission , String> usergroupPermRepo;
	
	@Autowired(required=false)	
	private UserGroupRepo<UserGroup , String> userGroupRepo;
	
	@Autowired(required = false)
	private SubjectManager subjectManager;	
	
	@Autowired(required=false)
	private PaginationManager paginationManager;	

	@Autowired(required=false)
	private BusinessEntityFactory entityFactory;		
	
	public edu.gtcfla.km.repositories.CategoryRepo<Category, String> getCategoryRepo() {
		return categoryRepo;
	}

	public void setCategoryRepo(edu.gtcfla.km.repositories.CategoryRepo<Category, String> categoryRepo) {
		this.categoryRepo = categoryRepo;
	}
	
	

	@Override
	public Set<UserDirectPermissionListVO> listUserPermission(
			String categoryId, String query) throws BusinessOperationException  {
		
		
		MapPaginaitionCriteria mpc = new MapPaginaitionCriteria();
		mpc.putValue("query",query);
		Page<User> pageResult =  userRepo.findAll(mpc);
		
		// --- get all user id --
		Collection<User> users = pageResult.getContent();
		Set<String> userIds = new LinkedHashSet<String>();
		for (User user : users) {
			userIds.add( user.getId() );
		}
		
		// --- find all perm by categoryId and userId ---
		final Map<String , UserPermission> upCateMap =  upRepo.findUserPermisionByCateAndUserIds(categoryId, userIds);
		
		
		PageItemConverter<User , UserDirectPermissionListVO> 
			itemConverter = new PageItemConverter<User , UserDirectPermissionListVO>() {
			public UserDirectPermissionListVO convert( User input ) {

				UserDirectPermissionListVO listView = new UserDirectPermissionListVO( );
				listView.setUserId( input.getId() );
				listView.setUserName(  input.getName() );
				
				UserPermission  up = upCateMap.get( input.getId() );
				if (up != null) {
					listView.setEntity( up );
				}
			
				return listView;
			}
		};
		
		Set<UserDirectPermissionListVO> contentList = null;
		
		try {

			Page<UserDirectPermissionListVO> newPage = (Page<UserDirectPermissionListVO>) paginationManager.convertItem(pageResult, itemConverter);
			
			// --- find perm for user ids ---
			contentList = new LinkedHashSet<UserDirectPermissionListVO>(newPage.getContent());

		
		} catch (PaginationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
		
			
		
		return contentList;
	}

	@Override
	public void updateUserPermissions(String categoryId,
			Set<UserDirectPermissionListVO> userPermisList)
			throws BusinessOperationException {
		
		// --- find all category under this category id ---
		Map<String , Category>  cateMap = categoryRepo.findAllMap();
		
		//  --- update all permission for every categories ---
		GenTreeModelBuilder<Category> genTreeModel = new GenTreeModelBuilder<Category>(cateMap);
		
		genTreeModel.generate();
		
		Map<String , TreeNode>  treeMap = genTreeModel.getResultMap();
		

		
		
		Set<UserPermission> newUpdatePermission = null;
		
		

		
		if (categoryId != null && categoryId.equals("root") ) {
			newUpdatePermission = new LinkedHashSet<UserPermission>();

			Set<TreeNode> allTreeNodeBaseRoot = genTreeModel.getResultSet();
			
			for (TreeNode treeNode : allTreeNodeBaseRoot) {
				newUpdatePermission.addAll( updateAllDepthPermission( treeNode ,  userPermisList ) ) ;
			}
			
		} else {
			TreeNode treeNode = treeMap.get(categoryId);
			newUpdatePermission = updateAllDepthPermission( treeNode ,  userPermisList );
			
		}

		
		
		// --- remove old permission ---

		Set<String> userIds = new LinkedHashSet<String>();
		Set<String> cateIds = new LinkedHashSet<String>();
		
		for (UserPermission up : newUpdatePermission) {
			userIds.add( up.getUserId() );
			cateIds.add( up.getCategoryId() );
		}

		upRepo.removeAllByCateUserIds( cateIds , userIds );
		
		// --- add new permisson ---
		upRepo.saveAll( newUpdatePermission );

		

	}
	
	private Set<UserPermission> updateAllDepthPermission(TreeNode treeNode , Set<UserDirectPermissionListVO> userPermisList) {
		
		Set<UserPermission> upSet = new LinkedHashSet<UserPermission>();
		
		// --- update tree node ---
		for (UserDirectPermissionListVO udpl : userPermisList) {
			UserPermission newEntity = entityFactory.create( UserPermission.class );
			BeanUtils.copyProperties( udpl.getEntity() , newEntity);
			newEntity.setCategoryId( treeNode.getId() );
			upSet.add( newEntity );
	
		}

		Collection<TreeNode> children = treeNode.getChildren();
		if (children != null && !children.isEmpty() ) {

			for (TreeNode child : children ) {
				Set<UserPermission> subAllPerms = updateAllDepthPermission(child , userPermisList);
				upSet.addAll( subAllPerms );
			}
			
		}
		
		return upSet;
		
	}

	@Override
	public Set<CurrentUserCategoryPermissionVO> getAllCategoryPermissionFormCurrentUser()
			throws BusinessOperationException {
		
		String currentAccountId = subjectManager.getCurrentAccountId();
		
		// --- get current group current permission --
		UserGroup userGroup = userGroupRepo.findFirstOneByUserId(currentAccountId);
		
		// --- usergroup perms
		Map<String, UserGroupPermission>  usergroupPerms = new LinkedHashMap<String , UserGroupPermission>();
		if (userGroup != null) {
			usergroupPerms = this.usergroupPermRepo.findUserGroupPermissionForCategories(userGroup.getId());
		}
	
		// --- user perms
		Map<String, UserPermission> userPerms =  upRepo.findUserPermissionForCategories( currentAccountId );
		
		Map<String, Category> cateMap = categoryRepo.findAllMap();
		
		// ---- get the view for only user group ---
		Map<String, Set<UserGroupPermission>>  cateSupportUserGroupPerms =  usergroupPermRepo.findUserGroupPermisionWithOnlyGroupCateView( cateMap.keySet() );
		
		Set<CurrentUserCategoryPermissionVO> cateuserPerms = new LinkedHashSet<CurrentUserCategoryPermissionVO>();
		
		for (Map.Entry<String, Category>  cateItem : cateMap.entrySet() ) {
			String key = cateItem.getKey();
			
			UserGroupPermission usergroup = usergroupPerms.get(key);
			UserPermission up = userPerms.get( key );
			Set<UserGroupPermission>  supportedOnlyGroupPerm =  cateSupportUserGroupPerms.get( key );
			Set<String> supportedOnlyGroupPermIds = new LinkedHashSet<String>();
			if (supportedOnlyGroupPerm != null &&   !supportedOnlyGroupPerm.isEmpty()) {
				for (UserGroupPermission ugp : supportedOnlyGroupPerm) {
					supportedOnlyGroupPermIds.add( ugp.getId() );
				}
			}
			
			
			CurrentUserCategoryPermissionVO cup = new CurrentUserCategoryPermissionVO();
			cup.setCategoryId( key );
			
			if (up != null && usergroup != null) {
				
				cup.setOnlyGroupCateView( usergroup.getOnlyGroupCateView() );
				cup.setCateView( (short) ( up.getCateView() | usergroup.getOnlyGroupCateView() ) );
				cup.setIsAdmin( (short)  (up.getIsAdmin() | usergroup.getIsAdmin() ) );
				cup.setCateAdding( (short) (up.getCateAdding() | usergroup.getCateAdding()) );
				cup.setCateEditing( (short) ( up.getCateEditing() | usergroup.getCateEditing() ) );
				cup.setCateDeleting( (short) ( up.getCateDeleting() | usergroup.getCateDeleting() ) );
				cup.setKmAdding( (short) ( up.getKmAdding() | usergroup.getKmAdding() ) );
				cup.setKmEditing( (short) ( up.getKmEditing() | usergroup.getKmEditing() )  );
				cup.setKmDeleting( (short)  (up.getKmDeleting() | usergroup.getKmDeleting() ) );
				cup.setKmView( (short) (up.getKmView() | usergroup.getKmView())  );
			}
			else if (up != null && usergroup == null) {
				
				cup.setCateView( up.getCateView()  );
				cup.setIsAdmin( up.getIsAdmin() );
				cup.setCateAdding( up.getCateAdding() );
				cup.setCateEditing( up.getCateEditing()  );
				cup.setCateDeleting( up.getCateDeleting()  );
				cup.setKmAdding(  up.getKmAdding() );
				cup.setKmEditing(  up.getKmEditing());
				cup.setKmDeleting( up.getKmDeleting() );
				cup.setKmView( up.getKmView()  );				
			}
			else if (up == null && usergroup != null) {
				
				String userGroupId = usergroup.getId();
				
				if (supportedOnlyGroupPermIds.contains( userGroupId ) ) {
					cup.setCateView( (short)1 );					
				}

				
				cup.setOnlyGroupCateView( !supportedOnlyGroupPermIds.isEmpty() ? (short)1 : 0 );
				cup.setIsAdmin( usergroup.getIsAdmin() );
				cup.setCateAdding( usergroup.getCateAdding() );
				cup.setCateEditing( usergroup.getCateEditing()  );
				cup.setCateDeleting( usergroup.getCateDeleting()  );
				cup.setKmAdding(  usergroup.getKmAdding() );
				cup.setKmEditing(  usergroup.getKmEditing());
				cup.setKmDeleting( usergroup.getKmDeleting() );
				cup.setKmView( usergroup.getKmView());				
			}
						
			cateuserPerms.add( cup );
			
			
		}
		
		return cateuserPerms;
	}

	
	

}
